package com.sailing.xjpb.orm.intercepter;

import com.google.common.collect.Sets;
import com.sailing.xjpb.orm.repository.SailingRepository;
import com.sailing.xjpb.orm.utils.MapResultTransformer;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 数据库信息获取初始化器<p/>
 * 所有业务代码中的类，如果使用了@PostConstruct注解的方法进行了数据库查询，则该类上需要加上注解@DependsOn("sailingDataBaseInfoHandler")，
 * 否则会因为SailingTenantTableInitialization该类还未进行初始化，拦截器TenantStatementInterceptor中使用该类会报空指针异常
 *
 * @author FanHaiChao
 * createDate 2024/1/29 12:29
 * @see com.sailing.xjpb.orm.intercepter.TenantStatementInterceptor
 */
public class SailingTenantTableInitialization {


    /**
     * 表名和字段的map
     */
    private final Set<String> tenantTableNameSet;
    /**
     * 查询数据库的Repository
     */
    private final SailingRepository sailingRepository;
    /**
     * jpa配置属性
     */
    private final JpaProperties jpaProperties;

    /**
     * 默认schema
     */
    private static final String DEFAULT_SCHEMA = "public";

    /**
     * 创建数据库信息处理器
     *
     * @param sailingRepository 数据库查询的Repository
     */
    public SailingTenantTableInitialization(SailingRepository sailingRepository, JpaProperties jpaProperties) {
        this.jpaProperties = jpaProperties;
        this.sailingRepository = sailingRepository;
        this.tenantTableNameSet = Sets.newHashSet();
        //初始化租户表名
        this.initTenantTableName();
    }

    /**
     * 是否是带租户的表（字段中有租户编码）
     *
     * @param tableName 表名
     * @return 是否是带租户的表-true:是，false:否
     */
    public boolean isTenantTable(String tableName) {
        if (CollectionUtils.isEmpty(tenantTableNameSet)) {
            return false;
        }
        return tenantTableNameSet.contains(tableName);
    }

    /**
     * 获取当前数据库连接scheam
     *
     * @return 当前数据库连接scheam
     */
    public String getCurrentSchema() {
        Map<String, String> properties = jpaProperties.getProperties();
        return properties.getOrDefault("hibernate.default_schema", DEFAULT_SCHEMA);
    }

    /**
     * 初始化多租户的表名
     */
    private void initTenantTableName() {
        //查询数据库的表名和字段名
        String sql = "select table_name,column_name from information_schema.COLUMNS where 1=1 and table_schema " +
                "=:currentSchema and table_name = any (array(SELECT tablename FROM pg_tables T inner JOIN pg_class C " +
                "on T.tablename = C.relname WHERE T.schemaname = :currentSchema and C.relispartition = 'f'));";
        //当前数据库连接的schema
        Map<String, Object> params = new HashMap<>(1);
        String currentSchema = this.getCurrentSchema();
        params.put("currentSchema", currentSchema);
        List<Map<String, Object>> tableColumnList = sailingRepository.listMap(sql, params,
                MapResultTransformer.INSTANCE);
        if (CollectionUtils.isEmpty(tableColumnList)) {
            return;
        }
        Set<String> tenantTableSet =
                tableColumnList.stream().filter(tableMap -> StringUtils.equals((String) tableMap.get("column_name"),
                        "tenant_code")).map(tableMap -> (String) tableMap.get("table_name")).collect(Collectors.toSet());
        tenantTableNameSet.addAll(tenantTableSet);
    }
}
